home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / sudo-1.000 / sudo-1 / sudo-1.2 / parse.c < prev    next >
C/C++ Source or Header  |  1993-06-11  |  14KB  |  404 lines

  1. /*
  2.  *  sudo version 1.1 allows users to execute commands as root
  3.  *  Copyright (C) 1991  The Root Group, Inc.
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 1, or (at your option)
  8.  *  any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  If you make modifications to the source, we would be happy to have
  20.  *  them to include in future releases.  Feel free to send them to:
  21.  *      Jeff Nieusma                       nieusma@rootgroup.com
  22.  *      3959 Arbol CT                      (303) 447-8093
  23.  *      Boulder, CO 80301-1752             
  24.  *
  25. ********************************************************************************
  26. * parse.c, sudo project
  27. * David R. Hieb
  28. * March 18, 1991
  29. *
  30. * routines to implement and maintain the parsing and list management.
  31. *******************************************************************************/
  32. #include <stdio.h>
  33. #include <strings.h>
  34. #include <ctype.h>
  35.  
  36. #include "sudo.h"
  37.  
  38. /* there are 3 main lists (User, Host_Alias, Cmnd_Alias) and 1 extra list */
  39. #define NUM_LISTS 3+1
  40.  
  41. extern char *user, *host, *cmnd;
  42. extern FILE *yyin, *yyout;
  43.  
  44. int user_list_found = FALSE;
  45. int list_num, new_list[NUM_LISTS];
  46. int parse_error = FALSE, found_user = FALSE;
  47. int next_type, num_host_alias = 0, num_cmnd_alias = 0;
  48. LINK tmp_ptr, reset_ptr, save_ptr, list_ptr[NUM_LISTS];
  49.  
  50. /*******************************************************************************
  51. * inserts a node into list 'list_num' and updates list_ptr[list_num]
  52. *******************************************************************************/
  53. void insert_member(list_num, token_type, op_type, data_string)
  54. int token_type, list_num;
  55. char op_type;
  56. char *data_string;
  57. {
  58.     tmp_ptr = (LINK)malloc(sizeof(LIST));
  59.     tmp_ptr->type = token_type;
  60.     tmp_ptr->op = op_type;
  61.     tmp_ptr->data = (char *)malloc(strlen(data_string)+1);
  62.     strcpy(tmp_ptr->data, data_string);
  63.     tmp_ptr->next = (new_list[list_num] == TRUE) ? NULL : list_ptr[list_num];
  64.  
  65.     list_ptr[list_num] = list_ptr[EXTRA_LIST] = tmp_ptr;
  66. }
  67.  
  68. /*******************************************************************************
  69. * diagnostic list printing utility that prints list 'list_num'
  70. *******************************************************************************/
  71. void print_list(list_num)
  72. int list_num;
  73. {
  74. LINK tmptmp_ptr;
  75.  
  76. tmptmp_ptr = list_ptr[list_num];
  77.  
  78. while (list_ptr[list_num] != NULL) {
  79.     printf("type = %d, op = %c, data = %s\n", list_ptr[list_num]->type,
  80.         list_ptr[list_num]->op, list_ptr[list_num]->data);
  81.     tmp_ptr = list_ptr[list_num];
  82.     list_ptr[list_num] = tmp_ptr->next;
  83.     }
  84. list_ptr[list_num] = tmptmp_ptr;
  85. }
  86.  
  87. /*******************************************************************************
  88. * delete list utility that deletes list 'list_num'
  89. *******************************************************************************/
  90. void delete_list(list_num)
  91. int list_num;
  92. {
  93. while (list_ptr[list_num] != NULL) {
  94.     tmp_ptr = list_ptr[list_num];
  95.     list_ptr[list_num] = tmp_ptr->next;
  96. /*  free(tmp_ptr);   */
  97.     }
  98. }
  99.  
  100. /*******************************************************************************
  101. * this routine is what the lex/yacc code calls to build the different lists.
  102. * once the lists are all built, control eventually returns to validate().
  103. *******************************************************************************/
  104. int call_back(token_type, op_type, data_string)
  105. int token_type;
  106. char op_type;
  107. char *data_string;
  108. {
  109. /* all nodes start out in the extra list since the node name is received last */
  110. list_num = EXTRA_LIST;
  111.  
  112. /*
  113.  * if the last received node is TYPE1, then we can classify the list
  114.  * and effectively transfer the extra list to the correct list type.
  115.  */
  116. if (token_type == TYPE1) {
  117.     /* we have just build a "Host_Alias" list */
  118.     if (strcmp(data_string, "Host_Alias") == 0) {
  119.         list_num = HOST_LIST;
  120.         if (num_host_alias > 0) {
  121.             reset_ptr->next = list_ptr[HOST_LIST];
  122.             }
  123.         num_host_alias++;
  124.         }
  125.     /* we have just build a "Cmnd_Alias" list */
  126.     else if (strcmp(data_string, "Cmnd_Alias") == 0) {
  127.         list_num = CMND_LIST;
  128.         if (num_cmnd_alias > 0) {
  129.             reset_ptr->next = list_ptr[CMND_LIST];
  130.             }
  131.         num_cmnd_alias++;
  132.         }
  133.     /* we have just build a "User" list */
  134.     else {
  135.         list_num = USER_LIST;
  136.         user_list_found = TRUE;
  137.         }
  138.     new_list[EXTRA_LIST] = TRUE;
  139.     new_list[list_num] = FALSE;
  140.     list_ptr[list_num] = list_ptr[EXTRA_LIST];
  141.     }
  142.  
  143. /* actually link the new node into list 'list_num' */
  144. insert_member(list_num, token_type, op_type, data_string);
  145.  
  146. if (new_list[list_num] == TRUE) {
  147.     reset_ptr = list_ptr[list_num];
  148.     new_list[list_num] = FALSE;
  149.     }
  150.  
  151. /*
  152.  * we process one user record at a time from the sudoers file. if we
  153.  * find the user were looking for, we return to lex/yacc declaring 
  154.  * that we have done so. otherwise, we reset the user list, delete the 
  155.  * nodes and start over again looking for the user.
  156.  */
  157. if (user_list_found == TRUE) {
  158.     if (list_ptr[list_num]->type == TYPE1 &&
  159.         strcmp(list_ptr[list_num]->data, user) == 0) {
  160.             return(FOUND_USER);
  161.             }
  162.         else {
  163.             new_list[list_num] = TRUE;
  164.             user_list_found = FALSE;
  165.             delete_list(list_num);
  166.             }
  167.     }
  168. return(NOT_FOUND_USER);
  169. }
  170.  
  171. /*******************************************************************************
  172. * this routine is called from cmnd_check() to resolve whether or not
  173. * a user is permitted to perform a to-yet-be-determined command for
  174. * a certain host name.
  175. *******************************************************************************/
  176. int host_type_ok()
  177. {
  178. /* check for the reserved keyword 'ALL'. if so, don't check the host name */
  179. if (strcmp(list_ptr[USER_LIST]->data, "ALL") == 0) {
  180.     return(TRUE);
  181.     }
  182. /* this case is the normal lowercase hostname */
  183. else if (isupper(list_ptr[USER_LIST]->data[0]) == FALSE) {
  184.     return(strcmp(list_ptr[USER_LIST]->data, host) == 0);
  185.     }
  186. /* by now we have a Host_Alias that will have to be expanded */
  187. else {
  188.     save_ptr = list_ptr[HOST_LIST];
  189.     while (list_ptr[HOST_LIST] != NULL) {
  190.         if ((list_ptr[HOST_LIST]->type == TYPE2) &&
  191.             (strcmp(list_ptr[HOST_LIST]->data, 
  192.                     list_ptr[USER_LIST]->data) == 0)) {
  193.             next_type = list_ptr[HOST_LIST]->next->type;
  194.             tmp_ptr = list_ptr[HOST_LIST]; 
  195.             list_ptr[HOST_LIST] = tmp_ptr->next;
  196.             while (next_type == TYPE3) {
  197.                 if (strcmp(list_ptr[HOST_LIST]->data, host) == 0) {
  198.                     list_ptr[HOST_LIST] = save_ptr;
  199.                     return(TRUE);
  200.                     }
  201.                 if (list_ptr[HOST_LIST]->next != NULL) {
  202.                     next_type = list_ptr[HOST_LIST]->next->type;
  203.                     tmp_ptr = list_ptr[HOST_LIST];
  204.                     list_ptr[HOST_LIST] = tmp_ptr->next;
  205.                     }
  206.                 else {
  207.                     next_type = ~TYPE3;
  208.                     }
  209.                 }
  210.             }
  211.         else {
  212.             tmp_ptr = list_ptr[HOST_LIST];
  213.             list_ptr[HOST_LIST] = tmp_ptr->next;
  214.             }
  215.         }
  216.     list_ptr[HOST_LIST] = save_ptr;
  217.     return(FALSE);
  218.     }
  219. }
  220.  
  221. /*******************************************************************************
  222. * this routine is called from cmnd_check() to resolve whether or not
  223. * a user is permitted to perform a certain command on the already
  224. * established host.
  225. *******************************************************************************/
  226. int cmnd_type_ok()
  227. {
  228. /* check for the reserved keyword 'ALL'. */
  229. if (strcmp(list_ptr[USER_LIST]->data, "ALL") == 0) {
  230.     /* if the command has an absolute path, let them do it */
  231.     if (cmnd[0] == '/') {
  232.         return(MATCH);
  233.         }
  234.     /* if the command does not have an absolute path, forget it */
  235.     else {
  236.         return(NO_MATCH);
  237.         }
  238.     }
  239. /* if the command has an absolute path, check it out */
  240. else if (list_ptr[USER_LIST]->data[0] == '/') {
  241.     /* op  |   data   | return value
  242.      *---------------------------------
  243.      * ' ' | No Match | return(NO_MATCH) 
  244.      * '!' | No Match | return(NO_MATCH) 
  245.      * ' ' |  A Match | return(MATCH) 
  246.      * '!' |  A Match | return(QUIT_NOW)
  247.      *
  248.      * these special cases are important in subtracting from the
  249.      * Universe of commands in something like:
  250.      *   user machine=ALL,!/bin/rm,!/etc/named ...
  251.      */
  252.     if (strcmp(list_ptr[USER_LIST]->data, cmnd) == 0) {
  253.         if (list_ptr[USER_LIST]->op == '!') {
  254.             return(QUIT_NOW);
  255.             }
  256.         else {
  257.             return(MATCH);
  258.             }
  259.         }
  260.     else {
  261.         return(NO_MATCH);
  262.         }
  263.     }
  264. /* by now we have a Cmnd_Alias that will have to be expanded */
  265. else {
  266.     save_ptr = list_ptr[CMND_LIST];
  267.     while (list_ptr[CMND_LIST] != NULL) {
  268.         if ((list_ptr[CMND_LIST]->type == TYPE2) &&
  269.             (strcmp(list_ptr[CMND_LIST]->data, 
  270.                     list_ptr[USER_LIST]->data) == 0)) {
  271.             next_type = list_ptr[CMND_LIST]->next->type;
  272.             tmp_ptr = list_ptr[CMND_LIST]; 
  273.             list_ptr[CMND_LIST] = tmp_ptr->next;
  274.             while (next_type == TYPE3) {
  275.                 if (strcmp(list_ptr[CMND_LIST]->data, cmnd) == 0) {
  276.                     if (list_ptr[USER_LIST]->op == '!') {
  277.                         list_ptr[CMND_LIST] = save_ptr;
  278.                         return(QUIT_NOW);
  279.                         }
  280.                     else {
  281.                         list_ptr[CMND_LIST] = save_ptr;
  282.                         return(MATCH);
  283.                         }
  284.                     }
  285.                 if (list_ptr[CMND_LIST]->next != NULL) {
  286.                     next_type = list_ptr[CMND_LIST]->next->type;
  287.                     tmp_ptr = list_ptr[CMND_LIST];
  288.                     list_ptr[CMND_LIST] = tmp_ptr->next;
  289.                     }
  290.                 else {
  291.                     next_type = ~TYPE3;
  292.                     }
  293.                 }
  294.             }
  295.         else {
  296.             tmp_ptr = list_ptr[CMND_LIST];
  297.             list_ptr[CMND_LIST] = tmp_ptr->next;
  298.             }
  299.         }
  300.     list_ptr[CMND_LIST] = save_ptr;
  301.     return(NO_MATCH);
  302.     }
  303. }
  304.  
  305. /*******************************************************************************
  306. * this routine is called from validate() after the call_back() routine
  307. * has built all the possible lists. this routine steps thru the user list
  308. * calling on host_type_ok() and cmnd_type_ok() trying to resolve whether
  309. * or not the user will be able to execute the command on the host.
  310. *******************************************************************************/
  311. int cmnd_check()
  312. {
  313. int return_code;
  314.  
  315. while (list_ptr[USER_LIST] != NULL) {
  316.     if ((list_ptr[USER_LIST]->type == TYPE2) && host_type_ok()) {
  317.         next_type = list_ptr[USER_LIST]->next->type;
  318.         tmp_ptr = list_ptr[USER_LIST]; 
  319.         list_ptr[USER_LIST] = tmp_ptr->next;
  320.         while (next_type == TYPE3) {
  321.             return_code = cmnd_type_ok();
  322.             if (return_code == MATCH) {
  323.                 return(VALIDATE_OK);
  324.                 }
  325.             else if (return_code == QUIT_NOW) {
  326.                 return(VALIDATE_NOT_OK);
  327.                 }
  328.             if (list_ptr[USER_LIST]->next != NULL) {
  329.                 next_type = list_ptr[USER_LIST]->next->type;
  330.                 tmp_ptr = list_ptr[USER_LIST];
  331.                 list_ptr[USER_LIST] = tmp_ptr->next;
  332.                 }
  333.             else {
  334.                 next_type = ~TYPE3;
  335.                 }
  336.             }
  337.         }
  338.     else {
  339.         tmp_ptr = list_ptr[USER_LIST];
  340.         list_ptr[USER_LIST] = tmp_ptr->next;
  341.         }
  342.     }
  343. return(VALIDATE_NOT_OK);
  344. }
  345.  
  346. /*******************************************************************************
  347. * this routine is called from the sudo.c module and tries to validate
  348. * the user, host and command triplet.
  349. *******************************************************************************/
  350. int validate()
  351. {
  352. FILE *sudoers_fp;
  353. int i, return_code;
  354.  
  355. if ((sudoers_fp = fopen(SUDOERS, "r")) == NULL ) {
  356.     perror(SUDOERS);
  357.     log_error( NO_SUDOERS_FILE );
  358.     exit(1);
  359.     }
  360.  
  361. yyin = sudoers_fp;
  362. yyout = stdout;
  363.  
  364. for (i = 0; i < NUM_LISTS; i++)
  365.     new_list[i] = TRUE;
  366.  
  367. /*
  368.  * yyparse() returns with one of 3 values: 0) yyparse() worked fine; 
  369.  * 1) yyparse() failed; FOUND_USER) the user was found and yyparse()
  370.  * was returned from prematurely.
  371.  */
  372. return_code = yyparse();
  373.  
  374. /* don't need to keep this open... */
  375. (void) fclose (sudoers_fp);
  376.  
  377. /* if a parsing error occurred, set return_code accordingly */
  378. if (parse_error == TRUE) {
  379.     return_code = PARSE_ERROR;
  380.     }
  381.  
  382. /* if the user was not found, set the return_code accordingly */
  383. if (found_user == FALSE) {
  384.     return_code = NOT_FOUND_USER;
  385.     }
  386.  
  387. /* handle the 3 cases individually &*/
  388. switch(return_code) {
  389.     case FOUND_USER:
  390.         return_code = cmnd_check();
  391.         delete_list(USER_LIST);
  392.         delete_list(HOST_LIST);
  393.         delete_list(CMND_LIST);
  394.         return(return_code);
  395.         break;
  396.     case NOT_FOUND_USER:    
  397.         return(VALIDATE_NO_USER);
  398.         break;
  399.     case PARSE_ERROR: 
  400.         return(VALIDATE_ERROR);
  401.         break;
  402.     }
  403. }
  404.